/* 
 * shamefully copy from AnFetion.
 * more see: http://code.google.com/p/anfetion/
 */

package person.bangbang.im.Androidgin.Fetion;

import person.bangbang.im.Androidgin.Util.Log;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Random;

import org.w3c.dom.Document;

public abstract class FetionBase {
    // public static final String USERAGENT = "IIC2.0/PC 3.1.0480";
    public static final String USERAGENT = "IIC2.0/PC " + Settings.FAKE_VERSION;
    public static final String CONTENTTYPE = "text/xml; charset=UTF-8";
    // public static final String CLIENT = "type=\"PC\" version=\"3.1.0480\" platform=\"W5.1\"";
    public static final String CLIENT = "type=\"PC\" version=\"" + Settings.FAKE_VERSION
            + "\" platform=\"W5.1\"";

    private ArrayList<IStatusChangedReceiver> statusChangedReceiver = new ArrayList<IStatusChangedReceiver>();

    public abstract boolean execute();

    public void addStatusChangedReceiver(IStatusChangedReceiver receiver) {
        this.statusChangedReceiver.add(receiver);
    }

    public void removeStatusChangedReceiver(IStatusChangedReceiver receiver) {
        this.statusChangedReceiver.remove(receiver);
    }

    protected void onStatusChanged(int oldStatus, int newStatus) {
        for (int i = 0; i < this.statusChangedReceiver.size(); i++) {
            //System.out.println(i + "====" + statusChangedReceiver.get(i));
            if (!this.statusChangedReceiver.get(i).FetionStatusChanged(oldStatus, newStatus)) return;
        }
    }

    protected void onSetText(String text) {
        for (int i = 0; i < this.statusChangedReceiver.size(); i++) {
            if (!this.statusChangedReceiver.get(i).FetionSetErrorText(text))
            ;
            return;
        }
    }

    protected static Document parseXmlDocument(String xml) {
        return StrUtil.parseXmlDocument(xml);
    }

    protected static String Byte2HexString(byte[] value) {
        String hexString = "";
        for (int i = 0; i < value.length; i++) {
            if (Integer.toHexString(value[i] & 0xFF).length() == 1) hexString += "0";
            hexString += Integer.toHexString(value[i] & 0xFF).toUpperCase();
        }
        return hexString;
    }

    protected static byte[] HexString2Bytes(String src) {
        int len = (src.length() / 2);
        byte[] result = new byte[len];
        char[] achar = src.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static byte toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }

    public static HashedPasswordParameter HashPassword(String password) {
        int salt = new Random().nextInt();
        try {
            return new HashedPasswordParameter(HashPassword(password, toByteArray(salt)), salt);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String HashPassword(String password, byte[] salt) throws NoSuchAlgorithmException,
            UnsupportedEncodingException {
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
        byte[] buffer = sha1.digest(password.getBytes("UTF8"));
        byte[] tmp = new byte[buffer.length + salt.length];
        System.arraycopy(salt, 0, tmp, 0, salt.length);
        System.arraycopy(buffer, 0, tmp, salt.length, buffer.length);
        buffer = sha1.digest(tmp);
        tmp = new byte[salt.length + buffer.length];
        System.arraycopy(salt, 0, tmp, 0, salt.length);
        System.arraycopy(buffer, 0, tmp, salt.length, buffer.length);
        return Byte2HexString(tmp);
    }

    public static String ComputeResponse(int fid, String nonce, String cnonce, String domain, String password)
            throws UnsupportedEncodingException, NoSuchAlgorithmException {
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
        byte[] begin = (String.valueOf(fid) + ":" + domain + ":").getBytes("UTF8");
        byte[] end = HexString2Bytes(password.substring(8));
        byte[] tmp = new byte[begin.length + end.length];
        System.arraycopy(begin, 0, tmp, 0, begin.length);
        System.arraycopy(end, 0, tmp, begin.length, end.length);
        byte[] key = sha1.digest(tmp);
        begin = key;
        end = (":" + nonce + ":" + cnonce).getBytes("UTF8");
        tmp = new byte[begin.length + end.length];
        System.arraycopy(begin, 0, tmp, 0, begin.length);
        System.arraycopy(end, 0, tmp, begin.length, end.length);
        byte[] h1 = md5.digest(tmp);
        byte[] h2 = md5.digest(("REGISTER:" + String.valueOf(fid)).getBytes("UTF8"));

        return Byte2HexString(md5.digest((Byte2HexString(h1) + ":" + nonce + ":" + Byte2HexString(h2))
                .getBytes("UTF8")));
    }

    protected static byte[] toByteArray(int iSource) {
        byte[] tmp = new byte[4];
        for (int i = 0; i < 4; i++) {
            tmp[i] = (byte) (iSource >> 8 * i & 0xFF);
        }
        return tmp;
    }

    protected static String CreateNonce() {
        Random random = new Random();
        int num1 = 0;
        int num2 = 0;
        int num3 = 0;
        int num4 = 0;
        num1 = random.nextInt();
        num2 = random.nextInt();
        num3 = random.nextInt();
        num4 = random.nextInt();
        if ((num1 >> 0x18) < 0x10) {
            num1 += 0x10000000;
        }
        if ((num2 >> 0x18) < 0x10) {
            num2 += 0x10000000;
        }
        if ((num3 >> 0x18) < 0x10) {
            num3 += 0x10000000;
        }
        if ((num4 >> 0x18) < 0x10) {
            num4 += 0x10000000;
        }
        String result = "";
        result += Integer.toHexString(num1);
        result += Integer.toHexString(num2);
        result += Integer.toHexString(num3);
        result += Integer.toHexString(num4);
        return result.toUpperCase();
    }
}
